package com.xu.sso.server.advisor;

import com.xu.sso.core.enums.ErrorMessage;
import com.xu.sso.core.exception.SSOException;
import com.xu.sso.core.model.BaseResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

@Aspect
@Component
@Slf4j
public class LoginApiAdvisor {

    @Around("execution(public * com.xu.sso.server.controller.LoginApiController.*(..))")
    public Object invokeAPI(ProceedingJoinPoint pjp) {
        String apiName = pjp.getSignature().getName();
        Class<?> returnClazz = ((MethodSignature) pjp.getSignature()).getReturnType();
        Object returnValue = null;
        try {
            returnValue = pjp.proceed();
            this.handleSuccess(returnValue);
        } catch (SSOException e) {
            returnValue = this.handleBusinessError(e, apiName, returnClazz);
        } catch (Throwable e1) {
            returnValue = this.handleSystemError(e1, apiName, returnClazz);
        }
        return returnValue;
    }

    private void handleSuccess(Object returnValue) {
        if (returnValue instanceof BaseResponse) {
            BaseResponse response = (BaseResponse) returnValue;
            if (StringUtils.isBlank(response.getCode())) {
                response.setCode(ErrorMessage.Success.getErrCode());
                response.setMsg(ErrorMessage.Success.getErrMsg());
            }
        }
    }

    private Object handleBusinessError(SSOException e, String apiName, Class<?> returnClazz) {
        log.error(">>>>>>>>>>>>>>>>> api error when do " + apiName + ":" + e.getMessage(), e);
        Object returnValue = createStubResponse(returnClazz);
        if (returnValue instanceof BaseResponse) {
            BaseResponse response = (BaseResponse) returnValue;
            response.setCode(e.getCode());
            response.setMsg(e.getMessage());
        }
        return returnValue;
    }

    private Object handleSystemError(Throwable e, String apiName, Class<?> returnClazz) {
        log.error(">>>>>>>>>>>>>>>>> unkonw error when do " + apiName + ":" + e.getMessage(), e);
        Object returnValue = createStubResponse(returnClazz);
        if (returnValue instanceof BaseResponse) {
            BaseResponse response = (BaseResponse) returnValue;
            response.setCode(ErrorMessage.UnknowError.getErrCode());
            response.setMsg(ErrorMessage.UnknowError.getErrMsg());
        }
        return returnValue;
    }

    private <T> T createStubResponse(Class<T> clazz) {
        try {
            return clazz.newInstance();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

}
